#pragma once
#include "httplib.h"
#include <curl/curl.h>
#include <string>
#include <sstream>
#include <mutex>
#include <vector>
#include <future>
#include "logger.h"

#include "jwt-cpp/jwt.h"  // 使用相对路径包含 jwt-cpp 头文件

#include <rapidjson/document.h>
#include <rapidjson/writer.h>
#include <rapidjson/stringbuffer.h>

// 节点信息
struct NodeInfo{
    std::string nodeId;
    std::string url;
    int role; // 0:leader 1:follower
};

struct NodePartitionInfo{
    int partitionId;
    std::vector<NodeInfo> nodes; // 存储具有相同partitionId的节点信息
};

struct NodePartitionConfig{
    std::string partitionKey_; // 分区key
    int numOfPartitions_;// 分区数量
    std::map<int, NodePartitionInfo> nodesInfo;
};

class ProxyServer{
public:
    ProxyServer(const std::string& masterServerHost,int masterServerPort,const std::string&instanceId);
    ~ProxyServer();
    void start(int port);
private:
    std::string masterServerHost_;//master server地址
    int masterServerPort_;//master server端口
    std::string instanceId_;//当前proxy所属实例id
    
    CURL* curlHandler_;
    httplib::Server httpServer_;

    std::vector<NodeInfo> nodes_[2];
    std::atomic<int> activeNodesIndex_;//当前活动的数组索引
    std::atomic<size_t> nextNodeIndex_;//轮询索引
    std::mutex nodesMutex_;
    bool running_;

    NodePartitionConfig nodePartions_[2];//两个数组无锁交替更新
    std::atomic<int> activePartitionIndex_; //当前活动的分区数组索引

    std::set<std::string> readPath_;//读请求的路径集合
    std::set<std::string> writePath_;//写请求的路径集合

    std::unordered_map<std::string, std::pair<std::string, std::string>> userCredentials_[2];
    std::atomic<int> activeUserCredentialsIndex_; // 指示当前活动的用户凭证数组索引

    void setupForwarding();
    void forwardRequest(const httplib::Request& req, httplib::Response& res,const std::string& path);
    void handleTopogyRequest(httplib::Response& res);
    void initCurl();
    void clearupCurl();
    static size_t writeCallBack(void* contents, size_t size, size_t nmemb, void* userp);
    void fetchAndUpdateNodes();//从master server获取节点信息并更新
    void startNodeUpdateTimer();//启动节点更新计时器

    bool extractParitionKeyValue(const httplib::Request& req, std::string& partitionKeyValue);
    int calculatePartitionId(const std::string& partitionKeyValue);
    bool selectTargetNode(const httplib::Request& req, int partitionId,const std::string& path,NodeInfo& targetNode);
    void forwardToTargetNode(const httplib::Request& req, httplib::Response& res,const std::string& path,const NodeInfo& targetNode);
    void broadcastRequestToAllPartitions(const httplib::Request& req, httplib::Response& res,const std::string& path);
    httplib::Response sendRequestToPartition(const httplib::Request& req,const std::string& path,int partitionId);
    void processAndRespondToBroadcast(httplib::Response& res,const std::vector<httplib::Response>& allResponses,uint k);

    //获取分区配置
    void fetchAndUpdatePartitionConfig();
    
    void startPartitionUpdateTimer();
    void fetchAndUpdateUserCredentials();
    void startUserCredentialsUpdateTimer();
    bool generateJwt(const std::string& username, std::string& jwtToken);

    void handleJwtTokenRequest(const httplib::Request& req, httplib::Response& res);
    bool validateCredentials(const std::string& username, const std::string& password);
    bool validateJwt(const std::string& jwtToken, std::string& username);
};